package gupao.concurrency.lock;

import gupao.concurrency.lock.utils.Utils;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class StarvationSample {

    static final BlockingQueue<Runnable> threadPoolTaskQueue = new LinkedBlockingDeque<Runnable>(){
        @Override
        public Runnable take() throws InterruptedException {
            return super.takeLast();
        }

        @Override
        public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {
            return super.pollLast(timeout, unit);
        }

        @Override
        public Runnable poll() {
            return super.pollLast();
        }
    };

    static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,1,1,TimeUnit.MINUTES, threadPoolTaskQueue);
    static volatile boolean starvationTaskFinished = false;
    static final Runnable starvationTask = () -> {
        log.info("starvation task run.");
        Utils.sleepIgnoreExp(200);
        starvationTaskFinished = true;
    };

    public static void main(String[] args) {
        threadPoolExecutor.submit(() -> {
           log.info("the first task is running.");
           Utils.sleepIgnoreExp(3000);
        });
        addStarvationTask();
        addRegularTasks();
        while(!starvationTaskFinished){
            Utils.sleepIgnoreExp(10);
        }
    }

    static void addStarvationTask(){
        log.info("add addStarvationTask");
        threadPoolExecutor.submit(starvationTask);
    }

    static void addRegularTasks(){
        Utils.sleepIgnoreExp(2000);
        for(int i = 0; i < 20; i++){
            String name = "rq-thread-" + i;
            threadPoolExecutor.submit(() -> {
                log.info("regular task {} is running.", name);
                Utils.sleepIgnoreExp(1000);
            });
            log.info("add regular task: {}", name);
            Utils.sleepIgnoreExp(1000);
        }
    }
}
